package server;

import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import common.body.TcpTunnelBody;
import common.container.SwitchContainer;
import common.enums.ProtocolEnum;
import common.pojo.Constant;
import common.pojo.TunnelInfoVO;
import common.utils.PropertiesUtil;
import lombok.extern.slf4j.Slf4j;
import server.container.HttpForwardServer;
import server.container.ProxyServer;
import server.container.TcpForwardServer;
import server.utils.CacheUtils;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static common.pojo.Constant.API_APP_VERSION_CHECK;
import static common.pojo.Constant.API_GET_CHANNEL_INFO;


/**
 * https://blog.csdn.net/qq_39165617/article/details/124641503
 *
 * @author gitama
 * @version 1.0
 * @date 2021/5/8 5:55 下午
 */
@Slf4j
public class ServerStartApp {

    //已启动的server代理
    public static LinkedHashMap<String, Boolean> startedServerMap = new LinkedHashMap();

    public static void main(String[] args) {
        String host = PropertiesUtil.getProperty("proxy.host", "0.0.0.0");
        List<TcpTunnelBody> defaultPorts = new ArrayList<>();
        defaultPorts.add(new TcpTunnelBody(ProtocolEnum.PROXY_SERVER, host, Integer.parseInt(PropertiesUtil.getProperty("proxy.port"))));
        defaultPorts.add(new TcpTunnelBody(ProtocolEnum.TCP, host, Integer.parseInt(PropertiesUtil.getProperty("tcpForward.port"))));
        defaultPorts.add(new TcpTunnelBody(ProtocolEnum.HTTP, host, Integer.parseInt(PropertiesUtil.getProperty("httpForward.port"))));
        defaultPorts.forEach(a -> {
            startProxy(a);
        });
        startHttpServer();
    }

    public static void startProxy(TcpTunnelBody tcpTunnelBody) {
        startProxy(tcpTunnelBody.getHost(), tcpTunnelBody.getPort(), tcpTunnelBody.getProtocolEnum());
    }

    /**
     * 添加映射
     *
     * @param proxyHost
     * @param proxyPort
     * @param protocolEnum
     */
    public static void startProxy(String proxyHost, Integer proxyPort, ProtocolEnum protocolEnum) {
        String key = proxyHost + ":" + proxyPort;
        Boolean isStart = startedServerMap.containsKey(key);
        if (isStart) {
            log.debug("{},is started", key);
            return;
        }
        startedServerMap.put(key, true);
        SwitchContainer container;
        switch (protocolEnum) {
            case HTTP:
                container = new HttpForwardServer(proxyHost, proxyPort);
                break;
            case TCP:
                container = new TcpForwardServer(proxyHost, proxyPort);
                break;
            case PROXY_SERVER:
                container = new ProxyServer(proxyHost, proxyPort);
                break;
            default:
                throw new RuntimeException("未知代理类型:" + protocolEnum);
        }
        Constant.SERVER_START_THREAD_POOL.execute(container::start);
    }

    /**
     * 开启http 服务器
     */
    public static void startHttpServer() {
        String port = PropertiesUtil.getProperty("http.port", "3434");
        JSONObject resInfo = new JSONObject();
        resInfo.put("info", "hi tio-server");
        resInfo.put("code", "200");
        resInfo.put("success", false);
        HttpUtil.createServer(Integer.valueOf(port))
                .addAction(API_GET_CHANNEL_INFO, (req, res) -> {
                    String method = req.getMethod();
                    //上下线不处理
                    if ("post".equalsIgnoreCase(method)){
                        res.write(resInfo.toString());
                    }
                    String token = req.getParam("token");
                    if (StrUtil.isBlank(token)) {
                        resInfo.put("info", "token is null");
                    } else {
                        //todo检测token是否合法
                        String proxyToken = PropertiesUtil.getProperty("proxy.port");
                        if (proxyToken.equalsIgnoreCase(token)) {
                            resInfo.put("info", "token is err");
                        } else {
                            Map<String, ProtocolEnum> enumMap = EnumUtil.getEnumMap(ProtocolEnum.class);
                            TcpTunnelBody tcpTunnelBody = new TcpTunnelBody();
                            String bsId = RandomUtil.randomString(10);
                            String tcpServerPort = PropertiesUtil.getProperty("tcpForward.port");
                            tcpTunnelBody.setBsId(bsId);
                            String protocol = "tcp";
                            tcpTunnelBody.setProtocol(protocol);
                            tcpTunnelBody.setProtocolEnum(enumMap.get(protocol.toUpperCase()));
                            tcpTunnelBody.setHost("192.168.31.120");
                            tcpTunnelBody.setPort(22);
                            tcpTunnelBody.setTime(System.currentTimeMillis());
                            tcpTunnelBody.setClientToken(token);
                            resInfo.put("data", tcpTunnelBody);
                            resInfo.put("success", true);
                            CacheUtils.set(tcpServerPort, JSON.toJSONString(tcpTunnelBody));
                        }
                    }
                    res.write(resInfo.toString());
                })
                .addAction(API_APP_VERSION_CHECK, (req, res) -> {
                    String version = req.getParam("version");
                    if (StrUtil.isBlank(version)) {
                        resInfo.put("info", "version is null");
                    }
                    res.write(resInfo.toString());
                })
                .start();
    }

}